/* PatternLexer.java
 * Author: liuex
 * 2007-12-16 ����03:37:34
 *
 * Note: 
 */
package org.lex.utils.logging.pattern;

import java.util.regex.PatternSyntaxException;

import org.lex.utils.SystemProperties;


public class PatternLexer {
	public static final String CONTROL_CHARS = "cdilmMnpt";
	private String pattern = "";
	private int offset = 0;

	public PatternLexer(String pattern) {
		this.pattern = pattern;
		this.offset = 0;
	}

	public boolean hasNext() {
		return offset < pattern.length();
	}

	public Pattern nextPattern() {
		if ('%' != pattern.charAt(offset)) {
			// we find an TextPattern, e.g. "Time: %6t"
			int end = pattern.indexOf('%', offset);
			if (-1 == end)
				end = pattern.length();
			String text = pattern.substring(offset, end);
			offset = end;
			return new TextPattern(text);
		} else {
			// FIXME "%%" pattern can't be recognised
			// we got a pattern has a pattern-control-char,
			// e.g. "%-5.8t{short}Time", "%-5.8tTime"
			int start = offset + 1; // '-'
			int controlChar = findNextControlChar(pattern, start);// 't'
			int end = controlChar + 1;// '{' or 'T'
			if (end < pattern.length() && '{' == pattern.charAt(end)) {
				// this pattern has a "{...}" part
				end = pattern.indexOf('}', end); // '}'
				if (-1 == end)
					throw new PatternSyntaxException("missing '}'", pattern, controlChar + 1);
				end++;
			}
			char ctrlChar = pattern.charAt(controlChar);
			String ps = pattern.substring(offset, end);
			this.offset = end;
			return this.createPattern(ctrlChar, ps);
		}
	}

	private Pattern createPattern(char ctrlChar, String ps) {
		Pattern pn = null;
		switch (ctrlChar) {
		case 'c':
			pn = new ClassNamePattern(ps);
			break;
		case 'd':
			pn = new DatePattern(ps);
			break;
		case 'i':
			pn = new ThreadIdPattern(ps);
			break;
		case 'l':
			pn = new LoggerNamePattern(ps);
			break;
		case 'm':
			pn = new MessagePattern(ps);
			break;
		case 'M':
			pn = new MethodNamePattern(ps);
			break;
		case 'n':
			pn = new TextPattern(SystemProperties.lineSeparator());
			break;
		case 'p':
			pn = new LevelPattern(ps);
			break;
		case 't':
			pn = new TimePattern(ps);
			break;
		}
		return pn;
	}

	static int findNextControlChar(String str, int startIndex) {
		while (startIndex < str.length()) {
			if (-1 != CONTROL_CHARS.indexOf(str.charAt(startIndex)))
				return startIndex;
			startIndex++;
		}
		return -1;
	}
}
